#include <retro.h>
#include "retro.library.h"
#include "retro.api.h"

using namespace Retro::Scripting;
using namespace Retro::Device;

#define API_BindKey(n) \
  { VK_##n, "KEY_" ## #n }

#define API_BindChar(n) \
  { #@n, "KEY_" ## #n }

#define API_AddStyle(s) \
  iScript->add(RETRO_##s, #s)

struct KeyBinding {
  INT   vkCode;
  PSTR  name;
} gKeyBinds[] = {
  API_BindKey(LBUTTON),
  API_BindKey(RBUTTON),
  API_BindKey(MBUTTON),

  API_BindKey(BACK),
  API_BindKey(TAB),

  API_BindKey(SHIFT),
  API_BindKey(CONTROL),
  API_BindKey(MENU),
  API_BindKey(ESCAPE),

  API_BindKey(SPACE),
  API_BindKey(PRIOR),
  API_BindKey(NEXT),
  API_BindKey(END),
  API_BindKey(HOME),

  API_BindKey(LEFT),
  API_BindKey(UP),
  API_BindKey(RIGHT),
  API_BindKey(DOWN),

  API_BindKey(INSERT),
  API_BindKey(DELETE),

  API_BindKey(NUMPAD0),
  API_BindKey(NUMPAD1),
  API_BindKey(NUMPAD2),
  API_BindKey(NUMPAD3),
  API_BindKey(NUMPAD4),
  API_BindKey(NUMPAD5),
  API_BindKey(NUMPAD6),
  API_BindKey(NUMPAD7),
  API_BindKey(NUMPAD8),
  API_BindKey(NUMPAD9),

  API_BindKey(F1),
  API_BindKey(F2),
  API_BindKey(F3),
  API_BindKey(F4),
  API_BindKey(F5),
  API_BindKey(F6),
  API_BindKey(F7),
  API_BindKey(F8),
  API_BindKey(F9),
  API_BindKey(F10),
  API_BindKey(F11),
  API_BindKey(F12),

  API_BindChar(0),
  API_BindChar(1),
  API_BindChar(2),
  API_BindChar(3),
  API_BindChar(4),
  API_BindChar(5),
  API_BindChar(6),
  API_BindChar(7),
  API_BindChar(8),
  API_BindChar(9),

  API_BindChar(A),
  API_BindChar(B),
  API_BindChar(C),
  API_BindChar(D),
  API_BindChar(E),
  API_BindChar(F),
  API_BindChar(G),
  API_BindChar(H),
  API_BindChar(I),
  API_BindChar(J),
  API_BindChar(K),
  API_BindChar(L),
  API_BindChar(M),
  API_BindChar(N),
  API_BindChar(O),
  API_BindChar(P),
  API_BindChar(Q),
  API_BindChar(R),
  API_BindChar(S),
  API_BindChar(T),
  API_BindChar(U),
  API_BindChar(V),
  API_BindChar(W),
  API_BindChar(X),
  API_BindChar(Y),
  API_BindChar(Z),
};

API_DeclareFunction(IsKeyDown)
{
  INT wIndex = iScript->getInt(1);

  WrapWnd wActive = GetFocus();

  if (wActive.getProcessId() != GetCurrentProcessId())
  {
    iScript->pushBool(FALSE);
  }
  else if (wIndex < 0 || wIndex >= sizeof(gKeyBinds) / sizeof(gKeyBinds[0]))
  {
    iScript->pushBool(FALSE);
  }
  else
  {
    iScript->pushBool(GetAsyncKeyState(gKeyBinds[wIndex].vkCode));
  }
}

API_DeclareFunction(PrintDebug)
{
  CHAR wLineFormat[1000];
  PCSTR wLine = iScript->getAnsi(1);

  if (wLine)
  {
    sprintf_s(wLineFormat, "Script >> %s\n", wLine);
    OutputDebugStringA(wLineFormat);
  }
}

API_DefineAPI(Scripting::InitializeAPI)
{
  API_AddFunction(PrintDebug);
  API_AddFunction(IsKeyDown);

  API_AddStyle(FONTTOP);
  API_AddStyle(FONTLEFT);
  API_AddStyle(FONTCENTER);
  API_AddStyle(FONTRIGHT);
  API_AddStyle(FONTVCENTER);
  API_AddStyle(FONTBOTTOM);
  API_AddStyle(FONTWORDBREAK);
  API_AddStyle(FONTSINGLELINE);
  API_AddStyle(FONTEXPANDTABS);
  API_AddStyle(FONTTABSTOP);
  API_AddStyle(FONTNOCLIP);
  API_AddStyle(WEIGHTTHIN);
  API_AddStyle(WEIGHTEXTRALIGHT);
  API_AddStyle(WEIGHTLIGHT);
  API_AddStyle(WEIGHTNORMAL);
  API_AddStyle(WEIGHTMEDIUM);
  API_AddStyle(WEIGHTSEMIBOLD);
  API_AddStyle(WEIGHTBOLD);
  API_AddStyle(WEIGHTEXTRABOLD);
  API_AddStyle(WEIGHTHEAVY);

  iScript->add(Display::MatrixWorld,        "MATRIXWORLD");
  iScript->add(Display::MatrixView,         "MATRIXVIEW");

  iScript->add(Display::DisplayWindowed,    "WINDOWED");
  iScript->add(Display::DisplayFullscreen,  "FULLSCREEN");

  for (INT i = 0; i < sizeof(gKeyBinds) / sizeof(KeyBinding); ++i)
    iScript->add(i, gKeyBinds[i].name);

  iScript->add(0, "KEY_FIRST");
  iScript->add(sizeof(gKeyBinds) / sizeof(KeyBinding) - 1, "KEY_LAST");
}
